/*!
 * \file MgwGapProxy.h
 * \brief Proxy for communication with Media Gateway via GAP protocol
 */

#ifndef SGW_MEDIA_GATEWAY_GAP_PROXY_H
#define SGW_MEDIA_GATEWAY_GAP_PROXY_H

#include <string>
#include <map>
#include "GapGenerator.h"
#include "RequestHandler.h"
#include "Message.h"

namespace tsc
{
namespace sgw
{

/**
 * Proxy for communication with Media Gateway via GAP protocol
 */
class MgwGapProxy
{
public:

	/**
	 * Returns singleton instance of the proxy
	 */
	static MgwGapProxy& instance();

	/**
	 * Initializes the proxy and specifies RequestHandler object
	 * which will be used as a communication entry point.
	 * This method must be called before any use of this proxy.
	 */
	static void init(common::RequestHandler* rh,
			         common::GeneratorEnvironment& ge);

	void handlePdu(common::Message*& msg);

	/**
	 * Clears all information related with this connection
	 * \param connectionId ID of the connection
	 */
	void clearConnection(uint32_t connectionId);

	bool sendGapConnectionCfm(GapGenerator& gapGen);

	bool sendGapConnectionRej(uint32_t                      mgwId,
							  GatewayApplicationPart::Cause cause);

	bool sendGapEchoReq(GapGenerator& gapGen);

	bool sendGapMediaBearerSetupReq(uint32_t connectionId,
	                                ProtocolsCommon::IpAddress* clientAddress,
	                                uint32_t clientMediaPort,
	                                uint32_t mediaItemId);

	bool sendGapMediaBearerRelease(uint32_t connectionId);

	/**
     * Adds mapping entry between mgwId and ID of
     * socket connection which handles this generator
     */
    void addConnIdMapping(uint32_t mgwId, unsigned int socketConnId);

    void clearConnIdMapping(uint32_t mgwId);

    /**
     * Finds ID of socket connection handling generator with specified mgwId
     */
    bool getSocketId(uint32_t mgwId,
                     unsigned int& socketConnId);

    common::RequestHandler* getRequestHandler();

private:

	/**
     * Handle GapPdu received from Media Gateway
     *
     * \param gapPdu the pdu to handle
     */
    void handleGapPdu(GatewayApplicationPart::GapPdu*& gapPdu,
                      unsigned int socketConnId);

    /**
     * Sends the provided encoded GAP message over GapSocket to the Media Gateway
     *
     * \param mgwId ID of MGW
     * \param msg encoded GAP message to send
     * \param pduNum GapPduNumber of the message to send
     * \return <code>true</code> on success, <code>false</code> otherwise
     */
    bool sendGapPdu(uint32_t                             mgwId,
                    const std::string&                   msg,
                    GatewayApplicationPart::GapPduNumber pduNum);

	MgwGapProxy(common::RequestHandler* rh,
			    common::GeneratorEnvironment& ge);

	~MgwGapProxy();

	/**
	 * Selects MGW which shall handle the specified connection
	 * and stores the selected generator in map
	 * \param connectionId ID of connection to handle
	 * \param gen pointer to GapGenerator which was selected
	 * \return true if suitable generator was found, false otherwise
	 */
	bool selectMgw(uint32_t connectionId, GapGenerator*& gen);

	/**
	 * Searches for already selected MGW for this connection
	 * \param connectionId ID of connection
	 * \param gen pointer to GapGenerator which was selected
	 * \return true if generator was found for this connection, false otherwise
	 */
	bool findMgw(uint32_t connectionId, GapGenerator*& gen);

	/**
	 * Mapping between connectionId (ID of UAP connection) and GapGenerator
	 * (i.e which MGW) which is handling this connection
	 */
	static std::map<uint32_t, GapGenerator*> msConnectionIdGapGeneratorMap;
	static MgwGapProxy* mInstance;
	common::RequestHandler* mpReqHandler;
	common::GeneratorEnvironment& _ge;

    // key=> mgwId, value=> socketConnId
    std::map<uint32_t, unsigned int> mSocketIdtoMgwIdMap;
};

} // namespace sgw
} // namespace tsc

#endif // SGW_MEDIA_GATEWAY_GAP_PROXY_H
